/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.util;

import cn.easyplatform.lang.Lang;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.apache.commons.io.IOUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public final class QCodeUtil {

    /**
     * 生成条形码
     *
     * @param contents
     * @param width
     * @param height
     * @return
     */
    public final static BufferedImage barcode(String contents, int width, int height) {
        int codeWidth = 3 + // start guard
                (7 * 6) + // left bars
                5 + // middle guard
                (7 * 6) + // right bars
                3; // end guard
        codeWidth = Math.max(codeWidth, width);
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
                    BarcodeFormat.EAN_13, codeWidth, height, null);
            return MatrixToImageWriter.toBufferedImage(bitMatrix);
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 生成条形码
     *
     * @param contents
     * @param width
     * @param height
     */
    public final static void barcode(String contents, int width, int height, String path) {
        int codeWidth = 3 + // start guard
                (7 * 6) + // left bars
                5 + // middle guard
                (7 * 6) + // right bars
                3; // end guard
        codeWidth = Math.max(codeWidth, width);
        FileOutputStream os = null;
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
                    BarcodeFormat.EAN_13, codeWidth, height, null);
            os = new FileOutputStream(new File(path));
            MatrixToImageWriter.writeToStream(bitMatrix, "png", os);
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        } finally {
            IOUtils.closeQuietly(os);
        }
    }

    /**
     * 生成二维码
     *
     * @param contents
     * @param width
     * @param height
     * @return
     */
    public final static BufferedImage qrcode(String contents, int width, int height) {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        // 指定纠错等级
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 指定编码格式
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        //设置二维码边的空度，非负数
        hints.put(EncodeHintType.MARGIN, 1);
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
                    BarcodeFormat.QR_CODE, width, height, hints);
            return MatrixToImageWriter.toBufferedImage(bitMatrix);
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 生成二维码
     *
     * @param contents
     * @param width
     * @param height
     * @return
     */
    public final static void qrcode(String contents, int width, int height, String path) {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        // 指定纠错等级
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        // 指定编码格式
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        //设置二维码边的空度，非负数
        hints.put(EncodeHintType.MARGIN, 1);
        FileOutputStream os = null;
        try {
            BitMatrix bitMatrix = new MultiFormatWriter().encode(contents,
                    BarcodeFormat.QR_CODE, width, height, hints);
            os = new FileOutputStream(new File(path));
            MatrixToImageWriter.writeToStream(bitMatrix, "jpg", os);
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        } finally {
            IOUtils.closeQuietly(os);
        }
    }

    /**
     * 生成带有Logo的二维码
     *
     * @param qrcode
     * @param logoFile
     * @return
     */
    public final static BufferedImage qrcodeLogo(BufferedImage qrcode, File logoFile) {
        try {
            Graphics2D g2 = qrcode.createGraphics();
            int matrixWidth = qrcode.getWidth();
            int matrixHeigh = qrcode.getHeight();
            /**
             * 读取Logo图片
             */
            BufferedImage logo = ImageIO.read(logoFile);
            //开始绘制图片
            g2.drawImage(logo, matrixWidth / 5 * 2, matrixHeigh / 5 * 2, matrixWidth / 5, matrixHeigh / 5, null);//绘制
            BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
            g2.setStroke(stroke);// 设置笔画对象
            //指定弧度的圆角矩形
            RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth / 5 * 2, matrixHeigh / 5 * 2, matrixWidth / 5, matrixHeigh / 5, 20, 20);
            g2.setColor(Color.white);
            g2.draw(round);// 绘制圆弧矩形
            //设置logo 有一道灰色边框
            BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
            g2.setStroke(stroke2);// 设置笔画对象
            RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth / 5 * 2 + 2, matrixHeigh / 5 * 2 + 2, matrixWidth / 5 - 4, matrixHeigh / 5 - 4, 20, 20);
            g2.setColor(new Color(128, 128, 128));
            g2.draw(round2);// 绘制圆弧矩形
            g2.dispose();
            qrcode.flush();
            return qrcode;
        } catch (IOException e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 识别条形码
     *
     * @param file
     * @return
     */
    public final static String decodeBarcode(String file) {
        try {
            BufferedImage image = ImageIO.read(new File(file));
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            Result result = new MultiFormatReader().decode(bitmap, null);
            return result.getText();
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 识别条形码
     *
     * @param image
     * @return
     */
    public final static String decodeBarcode(BufferedImage image) {
        try {
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            Result result = new MultiFormatReader().decode(bitmap, null);
            return result.getText();
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 识别条形码
     *
     * @param image
     * @return
     */
    public final static String decodeQrcode(BufferedImage image) {
        try {
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            //定义二维码参数
            Map<DecodeHintType, String> hints = new HashMap<>();
            hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
            Result result = new MultiFormatReader().decode(bitmap, hints);
            return result.getText();
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }

    /**
     * 识别条形码
     *
     * @param file
     * @return
     */
    public final static String decodeQrcode(String file) {
        try {
            BufferedImage image = ImageIO.read(new File(file));
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            //定义二维码参数
            Map<DecodeHintType, String> hints = new HashMap<>();
            hints.put(DecodeHintType.CHARACTER_SET, "utf-8");
            Result result = new MultiFormatReader().decode(bitmap, hints);
            return result.getText();
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }
}
